package znet

import (
	"fmt"
	"net"
	"zinx/utils"
	"zinx/ziface"
)

// Server IServer  接口实现,定义一个Server服务类
type Server struct {
	//服务器名称
	Name string
	//tcp4 or other
	IPVersion string
	//服务绑定的IP地址
	IP string
	//服务绑定的端口
	Port int
	//当前Server由用户绑定回调router，也就是Server注册的连接对应的处理业务
	//当前server的消息管理模块,用来绑定msgId和对应的处理方法
	msgHandle ziface.IMsgHandle
	//当前Server的连接管理器
	ConnMgr ziface.IConnManager

	//该Server连接创建时的Hook函数
	OnConnStart func(conn ziface.IConnection)
	//该Server连接断开时的Hook函数
	OnConnStop func(conn ziface.IConnection)
}

// Start 开启网络服务
func (s *Server) Start() {
	fmt.Printf("[START] Server listenner at IP：%s,Port %d,is starting \n", s.IP, s.Port)
	fmt.Printf("[Zinx] Version：%s,MaxConn：%d,MaxPacketSize：%d\n", utils.GlobalObject.Version,
		utils.GlobalObject.MaxConn, utils.GlobalObject.MaxPacketSize)
	//开启一个go去做服务器端Lister业务
	go func() {
		//0 启动worker工作机制
		s.msgHandle.StartWorkerPool()
		//1.获取一个TCP的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("resolve tcp addr err：", err)
			return
		}

		//2.监听服务器地址
		listenner, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listen", s.IPVersion, "err", err)
			return
		}
		//已经监听成功
		fmt.Println("start Zinx server", s.Name, "succ,now listening...")

		//TODO server.go 应该有一个自动生成ID的方法
		var cid uint32
		cid = 0
		//3.启动server网络连接业务
		for {
			//3.1 阻塞等待客户端建立连接请求
			conn, err := listenner.AcceptTCP()
			if err != nil {
				fmt.Println("Accept err", err)
				continue
			}
			//3.2 Server.Start() 设置服务器最大连接数控制, 如果超过最大连接，则关闭新的连接
			if s.GetConnMgr().Len() >= utils.GlobalObject.MaxConn {
				conn.Close()
				continue
			}
			//3.3 处理该新连接请求的业务方法,此时handler 和 conn 应该是绑定的
			dealConn := NewConnection(s, conn, cid, s.msgHandle)
			cid++

			//3.4 启动当前连接的处理业务
			go dealConn.Start()
		}
	}()
}
func (s *Server) Stop() {
	fmt.Println("[STOP] Zinx server,name ", s.Name)

	//将需要清理的连接信息或者其他信息一并停止或者清理
	s.ConnMgr.ClearConn()
}
func (s *Server) Serve() {
	s.Start()

	//TODO Server.Serve() 如果在启动服务的时候还要处理其他的事情，则可以在这里添加

	//阻塞，否则主Go退出,listenner 的go将会退出
	select {}
}

//路由功能：给当前服务注册一个路由业务方法，供客户端连接处理使用
func (s *Server) AddRouter(msgId uint32, router ziface.IRouter) {
	s.msgHandle.AddRouter(msgId, router)
	fmt.Println("Add Router succ! ")
}

func NewServer(name string) ziface.IServer {
	//先初始化全局配置文件
	utils.GlobalObject.Reload()

	s := &Server{
		Name:      utils.GlobalObject.Name,
		IPVersion: "tcp4",
		IP:        utils.GlobalObject.Host,
		Port:      utils.GlobalObject.TcpPort,
		msgHandle: NewMsgHandle(),
		ConnMgr:   NewConnManager(),
	}
	return s
}

// GetConnMgr 得到连接管理
func (s *Server) GetConnMgr() ziface.IConnManager {
	return s.ConnMgr
}

// SetOnConnStart 设置Server连接创建时的Hook函数
func (s *Server) SetOnConnStart(hookFunc func(ziface.IConnection)) {
	s.OnConnStart = hookFunc
}

// SetOnConnStop 设置Server连接断开时的Hook函数
func (s *Server) SetOnConnStop(hookFunc func(ziface.IConnection)) {
	s.OnConnStop = hookFunc
}

// CallOnConnStart 调用连接 OnConnStart Hook函数
func (s *Server) CallOnConnStart(conn ziface.IConnection) {
	if s.OnConnStart != nil {
		fmt.Println("--->CallOnConnStart")
		s.OnConnStart(conn)
	}
}

// CallOnConnStop 调用连接 OnConnStop Hook函数
func (s *Server) CallOnConnStop(conn ziface.IConnection) {
	if s.OnConnStop != nil {
		fmt.Println("--->CallOnConnStop")
		s.OnConnStop(conn)
	}
}
